package com.ls.utils.redis;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * <p>
 * redis工具类支持哨兵集群，和单机版
 * </p>
 *
 * @author TangQuanBin
 * @since 2019/10/11 19:28
 */
@Component
public class RedisClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisClient.class);

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 公司前缀+id 对应 公司信息
     */
    public static final String COMPANY_PREFIX = "COMPANY";


    /**
     * 是否已经存在某个key
     *
     * @param key key
     * @return true-存在，false-不存在
     */
    public boolean existsKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("Redis检查KEY异常{}", e.getMessage());
            return false;
        }
    }

    /**
     * 设置超时时间
     *
     * @param key    key
     * @param expire 超时时间，单位 秒
     * @return true-成功，false-失败
     */
    public boolean setExpireTime(String key, int expire) {
        try {
            if (expire > 0) {
                redisTemplate.expire(key, expire, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("Redis设置超时时间异常{}", e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 设置今天晚上过期
     *
     * @param key
     * @return
     */
    public boolean setExpireTimeByToDay(String key) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR, 23);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.MILLISECOND, 999);
        int expire = (int) ((cal.getTimeInMillis() - System.currentTimeMillis()) / 1000);
        return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    /**
     * 设置月底过期
     *
     * @param key
     * @return
     */
    public boolean setExpireTimeByMonth(String key) {
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        cal.set(year, month + 1, 1);
        cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH) - 1);
        cal.set(Calendar.HOUR, 23);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.MILLISECOND, 999);
        int expire = (int) ((cal.getTimeInMillis() - System.currentTimeMillis()) / 1000);
        return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    /**
     * add single redis cache
     *
     * @param key   redis key
     * @param field redis field
     * @param value redis value
     * @return if add success
     */
    public boolean save(String key, String field, Object value) {
        String valueJson = null;
        try {
            valueJson = JSONObject.toJSONString(value);
            redisTemplate.opsForHash().put(key, field, valueJson);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("保存Redis数据异常，key={},field={},valueJson={},e={}", key, field, valueJson, e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * add single redis cache
     *
     * @param key       redis key
     * @param field     redis field
     * @param valueJson redis value in json format
     * @return if add success
     */
    public boolean save(String key, String field, String valueJson) {
        try {
            redisTemplate.opsForHash().put(key, field, valueJson);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("保存Redis数据异常，key={},field={},valueJson ={},e={}", key, field, valueJson, e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 保存key-value
     *
     * @param key   key
     * @param value value
     * @return 是否成功
     */
    public boolean save(String key, String value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("保存Redis数据异常，key={},value ={},e={}", key, value, e.getMessage());
            return false;
        }
        return true;
    }


    /**
     * 查询数据
     *
     * @param key 查询key
     * @return
     */
    public String getJsonString(String key) {
        return redisTemplate.opsForValue().get(key);
    }


    /**
     * get all cached data in given redis key
     *
     * @param key redis key
     * @return all cached data,key is redis field
     */
    public Map<Object, Object> getAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取key-value的直接value，针对直接存储key-value的数据
     *
     * @param key   key
     * @param clazz value的类
     * @param <T>   value的类
     * @return 转化成Java对象的value值
     */
    public <T> T getValue(String key, Class<T> clazz) {
        JSONObject json = JSONObject.parseObject(redisTemplate.opsForValue().get(key));
        return JSONObject.toJavaObject(json, clazz);
    }


    /**
     * get a redis cache
     *
     * @param key   redis key
     * @param field redis field
     * @return redis value in json format
     */
    public String hget(String key, String field) {
        return (String) redisTemplate.opsForHash().get(key, field);
    }

    /**
     * get a redis cache
     *
     * @param key   redis key
     * @param field redis field
     * @param clazz redis value type
     * @return redis cache value
     */
    public <T> T hget(String key, String field, Class<T> clazz) {
        String jsonData = (String) redisTemplate.opsForHash().get(key, field);
        if (StringUtils.isNotBlank(jsonData)) {
            JSONObject jsonCacheObj = JSONObject.parseObject(jsonData);
            return JSONObject.toJavaObject(jsonCacheObj, clazz);
        }
        return null;
    }


    /**
     * get a redis cache
     *
     * @param key   redis key
     * @param field redis field
     * @param clazz redis value type
     * @return redis cache value
     * @author pengyu
     */
    public List getList(String key, String field, Class clazz) {
        String jsonData = (String) redisTemplate.opsForHash().get(key, field);
        if (StringUtils.isNotBlank(jsonData)) {
            JSONArray jsonArray = JSONArray.parseArray(jsonData);
            return JSONObject.parseArray(jsonArray.toJSONString(), clazz);
        }
        return null;


    }

    /**
     * delete all redis cache in given key
     *
     * @param key redis key
     * @return if delete success
     */
    public boolean delete(String key) {
        return redisTemplate.delete(key);
    }


    /**
     * delete redis cache in given key and fields
     *
     * @param key    redis key
     * @param fields redis fields
     * @return if delete success
     */
    public boolean deleteByHdel(String key, String... fields) {
        try {
            redisTemplate.opsForHash().delete(key, (Object) fields);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}
